package model.editormodel;

import java.util.HashMap;
import java.util.Map;
import model.LogicType;

/**
 * <b>Funktion:</b> Dient zur Speicherung aller benoetigten Daten eines
 * logischen Elements.<br>
 * <b>In Verbindung stehende Klassen:</b> <code>LogicType, Input, Output</code> <br>
 * <br>
 * Diese Klasse beinhaltet alle benoetigten Informationen eines logischen
 * Bauteils. Dies umfasst die Koordinaten in Pixel, den logischen Typ, Ein- und
 * Ausgaenge und den eindeutigen Namen.
 * 
 * @author Team Locsi
 * 
 */
public class LogicEditorElement {

	private LogicType type;
	private String distinctName;
	protected Map<String, Input> inputs;
	protected Map<String, Output> outputs;
	private double xCoord;
	private double yCoord;

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>LogicEditorElement</code> -
	 * Objekt.
	 * 
	 * @param type
	 *            <code>LogicType</code> - Art des
	 *            <code>LogicEditorElement</code>
	 * @param distinctName
	 *            <code>String</code> - Eindeutiger Name
	 * @param x
	 *            <code>double</code> - x-Koordinate des
	 *            <code>LogicEditorElement</code> in Pixel
	 * @param y
	 *            <code>double</code> - y-Koordinate des
	 *            <code>LogicEditorElement</code> in Pixel
	 * @throws <code>IllegalArgumetnException</code>, falls null bei
	 *         <code>LogicType</code> oder beim Namen uebergeben wird
	 */
	public LogicEditorElement(LogicType type, String distinctName, double x,
			double y) {

		// Die Uebergabeparameter LogicType und distinctName duerfen nicht null
		// sein
		if (type == null || distinctName == null) {
			throw new IllegalArgumentException(
					"uebergabeparameter darf nicht null sein");
		} else {
			this.type = type;
			this.xCoord = x;
			this.yCoord = y;
			this.inputs = new HashMap<String, Input>();
			this.outputs = new HashMap<String, Output>();
			this.distinctName = distinctName;
			createInputsAndOutputs();
		}
	}

	/**
	 * AND,OR,XOR,NAND haben zwei Eingaenge ('a' und 'b') und ein Ausgang ('o')
	 * 
	 * SWITCH, LAMP, CLOCK, NOT haben ein Eingang ('a') und ein Ausgang ('o')
	 * 
	 * FLIPFLOP: Eingaenge: 'set','reset', Ausgaenge: 'q', 'nq' TWO_MX:
	 * Eingaenge: 'a','b','select', Ausgang: 'o' SELFDEFINED: passiert hier gar
	 * nix.. methode wird ueberschrieben in LogicSelfdefinedEditorElement
	 */
	private void createInputsAndOutputs() {
		if (this.type != LogicType.SELFDEFINED) {
			if (this.type != LogicType.FLIPFLOP) {
				this.inputs.put(Input.STD_A, new Input(this));
				this.outputs.put(Output.STD_O, new Output(this));
			}
			if (LogicType.AND_OR_XOR_NAND_TWOMX.contains(this.type)) {
				this.inputs.put(Input.STD_B, new Input(this));
			}
			if (this.type == LogicType.TWO_MX) {
				this.inputs.put(Input.SELECT, new Input(this));
			}
			if (this.type == LogicType.FLIPFLOP) {
				this.inputs.put(Input.FF_SET, new Input(this));
				this.inputs.put(Input.FF_RESET, new Input(this));
				this.outputs.put(Output.FF_Q, new Output(this));
				this.outputs.put(Output.FF_NQ, new Output(this));
			}
		}
	}

	/**
	 * Setzt den Namen des <code>LogicEditorElement</code>.
	 * 
	 * @param name
	 *            <code>String</code> - Name des <code>LogicEditorElement</code>
	 * @throws <code>IllegalArgumetnException</code>, falls null uebergeben wird
	 */
	protected void setName(String name) {

		// Der Uebergabeparameter name darf nicht null sein
		if (name == null) {
			throw new IllegalArgumentException("name darf nicht null sein");
		} else {
			this.distinctName = name;
		}
	}

	/**
	 * Gibt den Namen des <code>LogicEditorElement</code> zurueck.
	 * 
	 * @return <code>String</code> - den Namen des
	 *         <code>LogicEditorElement</code>
	 */
	public String getName() {
		return this.distinctName;
	}

	/**
	 * Gibt die zugehoerigen <code>Input</code>-Objekte des
	 * <code>LogicEditorElement</code> zurueck.
	 * 
	 * @return <code>Map</code><<code>String, Input></code> - die zugehoerigen
	 *         <code>Input<code>-Objekte des <code>LogicEditorElement</code>
	 */
	public Map<String, Input> getInputs() {
		return inputs;
	}

	/**
	 * Gibt die zugehoerigen <code>Output</code>-Objekte des
	 * <code>LogicEditorElement</code> zurueck.
	 * 
	 * @return <code>Map</code><<code>String, Output></code> - die zugehoerigen
	 *         <code>Output</code>-Objekte des <code>LogicEditorElement</code>
	 */
	public Map<String, Output> getOutputs() {
		return outputs;
	}

	/**
	 * Gibt die Art des <code>LogicEditorElement</code> zurueck.
	 * 
	 * @return <code>LogicType</code> - die Art des
	 *         <code>LogicEditorElement</code>
	 */
	public LogicType getType() {
		return type;
	}

	/**
	 * Setzt die x-Koordinate des <code>LogicEditorElement</code> in Pixel.
	 * 
	 * @param xCoord
	 *            <code>double</code> - x-Koordinate des
	 *            <code>LogicEditorElement</code> in Pixel
	 */
	protected void setXCoord(double xCoord) {
		this.xCoord = xCoord;
	}

	/**
	 * Gibt die x-Koordinate des <code>LogicEditorElement</code> in Pixel
	 * zurueck.
	 * 
	 * @return <code>double</code> - die x-Koordinate des
	 *         <code>LogicEditorElement</code> in Pixel
	 */
	public double getXCoord() {
		return xCoord;
	}

	/**
	 * Setzt die y-Koordinate des <code>LogicEditorElement</code> in Pixel.
	 * 
	 * @param yCoord
	 *            <code>double</code> - y-Koordinate des
	 *            <code>LogicEditorElement</code> in Pixel
	 */
	protected void setYCoord(double yCoord) {
		this.yCoord = yCoord;
	}

	/**
	 * Gibt die y-Koordinate des <code>LogicEditorElement</code> in Pixel
	 * zurueck.
	 * 
	 * @return <code>double</code> - die y-Koordinate des
	 *         <code>LogicEditorElement</code> in Pixel
	 */
	public double getYCoord() {
		return yCoord;
	}
}